package com.jfs.security.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.jfs.entity.User;
import com.jfs.result.Result;
import com.jfs.security.authentication.JwtAuthenticationToken;
import com.jfs.security.authentication.SessionManager;
import com.jfs.security.properties.SecurityProperties;
import com.jfs.security.service.LoginService;
import com.jfs.security.service.UserService;
import com.jfs.security.session.SessionCleanReactor;
import com.jfs.security.utils.HttpServletUtils;
import com.jfs.security.utils.JwtTokenUtils;
import com.jfs.security.vo.LoginUserVo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.Objects;

/**
 * @Description 登录实现类
 * @E-mail cwm3412638@163.com
 * @Author cwm
 * @Date 2022/8/5
 */
@Service
@Slf4j
@AllArgsConstructor
public class LoginServiceImpl implements LoginService {
    private AuthenticationManager authenticationManager;
    private SecurityProperties securityProperties;
    private final UserService userService;
    private final SessionCleanReactor sessionCleanReactor;

    @Override
    @Transactional
    public Result<String> login(LoginUserVo loginUserVo) {
        //判断当前用户是否已经登录过
        String token = SessionManager.getSession(loginUserVo.getUsername());
        if (StrUtil.isNotEmpty(token)) {
            //说明以经登录了 把登录token置为失效
            SessionManager.setIsLoginExpir(token);
            Date tokenExpiredTime = JwtTokenUtils.getTokenExpiredTime(token, securityProperties.getSecret());
            long time = DateUtil.date().getTime();
            if (Objects.nonNull(tokenExpiredTime) && !JwtTokenUtils.isTokenExpired(token, securityProperties.getSecret())) {
                //清除会话
                sessionCleanReactor.cleanSession(token, (tokenExpiredTime.getTime() - time));
            }
        }
        JwtAuthenticationToken jwtAuthenticationToken = new JwtAuthenticationToken(loginUserVo.getUsername(), loginUserVo.getPassword());
        jwtAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(HttpServletUtils.getHttpServletRequest()));
        // 执行登录认证过程
        Authentication authentication = authenticationManager.authenticate(jwtAuthenticationToken);
        // 认证成功存储认证信息到上下文
        SecurityContextHolder.getContext().setAuthentication(authentication);
        String nweToken = JwtTokenUtils.generateToken(authentication, securityProperties.getExpireTime(), securityProperties.getSecret());
        //记录会话
        SessionManager.setSession(loginUserVo.getUsername(), nweToken);
        //记录用户登录时间
        userService.update(Wrappers.<User>lambdaUpdate()
                .set(User::getLastLoginTime, DateUtil.date())
                .eq(User::getUsername, loginUserVo.getUsername())
        );
        return Result.success("登录成功", nweToken);
    }

}
